package de.hwr.sudokuspielehr.ui.listener;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import javax.swing.BorderFactory;

import de.hwr.sudokuspielehr.data.Sudoku;
import de.hwr.sudokuspielehr.ui.UserInterface;
import de.hwr.sudokuspielehr.ui.component.SudokuCellPanel;

public class TipButtonListener implements ActionListener {

	/**
	 * 
	 */
	private UserInterface ui;

	/**
	 * 
	 * @param pUi
	 */
	public TipButtonListener(UserInterface pUi) {
		ui = pUi;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		Sudoku s = ui.getSudoku();
		randomTip(s, 0);
	}

	/**
	 * 
	 */
	private void randomTip(Sudoku pSudoku, int pCounter) {
		if (pCounter > 50) {
			ui.setStatus("Ich konnte keine Tipps finden!");
			return;
		}

		ui.clearHighlightedIndices();
		Random r = new Random();
		List<Integer> indices = null;
		int result = -1;

		switch (r.nextInt(5)) {
		case 0:
			result = obviousNumberTip(pSudoku);
			indices = (result == -1) ? null : Arrays.asList(result);
			ui.setStatus(UserInterface.TIP_ELIMINATE);
			break;
		case 1:
			result = lineNumberTip(pSudoku, true);
			indices = (result == -1) ? null : Arrays.asList(result);
			ui.setStatus(UserInterface.TIP_ROWS);
			break;
		case 2:
			result = lineNumberTip(pSudoku, false);
			indices = (result == -1) ? null : Arrays.asList(result);
			ui.setStatus(UserInterface.TIP_COLUMNS);
			break;
		case 3:
			result = groupNumberTip(pSudoku);
			indices = (result == -1) ? null : Arrays.asList(result);
			ui.setStatus(UserInterface.TIP_GROUP);
			break;
		case 4:
			result = scanTip(pSudoku);
			indices = (result == -1) ? null : Arrays.asList(result);
			ui.setStatus(UserInterface.TIP_SCAN);
			break;
		}

		if (indices == null) {
			pCounter++;
			randomTip(pSudoku, pCounter);
		} else {
			highlightCells(indices);
		}
	}

	/**
	 * 
	 * @param pSudoku
	 */
	private int lineNumberTip(Sudoku pSudoku, boolean pHorizontal) {
		int[] board = pSudoku.getBoard();
		for (int i = 0; i < 9; i++) {
			int emptyCells = 0;
			int index = -1;

			for (int j = 0; j < 9; j++) {
				int currentIndex;
				if (pHorizontal) {
					currentIndex = i * 9 + j;
				} else {
					currentIndex = j * 9 + i;
				}

				if (board[currentIndex] == Sudoku.EMPTY_CELL_VALUE) {
					index = currentIndex;
					emptyCells++;
				}
			}

			if (emptyCells == 1) {
				return index;
			}
		}
		return -1;
	}

	/**
	 * 
	 * @return
	 */
	private int scanTip(Sudoku pSudoku) {
		for (int i = 1; i <= 9; i++) {
			for (int y = 0; y < 3; y++) {
				for (int x = 0; x < 3; x++) {
					if (pSudoku.scanSingleGroupForNumber(x, y, i)) {
						int[][] group = pSudoku.getGroup(x, y);
						for (int yy = 0; yy < 3; yy++) {
							for (int xx = 0; xx < 3; xx++) {
								if (group[xx][yy] == i) {
									int currentX = x * 3 + xx;
									int currentY = y * 3 + yy;
									int currentIndex = currentY * 9 + currentX;
									pSudoku.setCell(currentIndex, -1);
									return currentIndex;
								}
							}
						}
					}
				}
			}
		}

		return -1;
	}

	/**
	 * 
	 * @return
	 */
	private int groupNumberTip(Sudoku pSudoku) {
		for (int y = 0; y < 3; y++) {
			for (int x = 0; x < 3; x++) {
				int[][] currentGroup = pSudoku.getGroup(x, y);

				int emptyCells = 0;
				int index = -1;

				for (int i = 0; i < 3; i++) {
					for (int j = 0; j < 3; j++) {
						if (currentGroup[j][i] == -1) {
							int currentX = x * 3 + j;
							int currentY = y * 3 + i;
							index = currentY * 9 + currentX;
							emptyCells++;
						}
					}
				}

				if (emptyCells == 1) {
					return index;
				}
			}
		}
		return -1;
	}

	/**
	 * 
	 * @param pSudoku
	 * @return
	 */
	private int obviousNumberTip(Sudoku pSudoku) {
		int[] board = pSudoku.getBoard();
		for (int i = 0; i < board.length; i++) {
			if (board[i] == Sudoku.EMPTY_CELL_VALUE) {
				if (pSudoku.getPossibleNumbersA(i).size() == 1) {
					return i;
				}
			}
		}
		return -1;
	}

	/**
	 * 
	 * @param i
	 */
	private void highlightCells(List<Integer> pList) {
		for (int n : pList) {
			for (SudokuCellPanel scp : ui.getCellPanels()) {
				if (scp.getIndex() == n) {
					scp.setBorder(BorderFactory.createLineBorder(new Color(0, 100, 0)));
					scp.setBackground(new Color(210, 255, 210));
				}
			}
		}
		ui.setHighlightedIndices(pList);
	}
}
